//
// Created by demo on 2022/11/16.
//

#include "mnq.h"
#include <iostream>
#include <jni.h>
#include <string>
#include <android/log.h>
#include <string.h>
#include <stdio.h>

using namespace std;

static string appList[] = {
        "com.bly.dkplat",//多开分身本身的包名
        "com.lbe.parallel",//平行空间
        "com.excelliance.dualaid",//双开助手
        "com.qihoo.magic",//360分身大师
        "com.dual.dualgenius" //DualGenius/双开精灵
};
extern "C" jboolean Java_com_banban_kuxiu_framework_exception_Mnq_mnq(JNIEnv *env, jclass type) {
    jboolean check = checkmnq(env);
    if (check) {
        exitApp(env);
    }
    return check;
}

jboolean checkmnq(JNIEnv *env) {

    jobject application = getApplication(env);
    jclass contextClass = env->GetObjectClass(application);

    jmethodID getFilesDir = env->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");

    jobject filesDir = env->CallObjectMethod(application, getFilesDir);

    jclass fileClass = env->FindClass("java/io/File");

    jmethodID getPath = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;");

    jstring path = (jstring) env->CallObjectMethod(filesDir, getPath);

    jmethodID methodID_packagename = env->GetMethodID(contextClass,
                                                      "getPackageName", "()Ljava/lang/String;");
    jstring packageName = (jstring) env->CallObjectMethod(application, methodID_packagename);


    jstring tagetPath = env->NewStringUTF("/data/user/0/");
    tagetPath = concat(env, tagetPath, packageName);
    tagetPath = concat(env, tagetPath, env->NewStringUTF("/files"));

    jboolean equal = equals(env, tagetPath, path);

//    __android_log_print(ANDROID_LOG_INFO, "sssss check", " %s ",
//                        env->GetStringUTFChars(tagetPath, NULL));
//    __android_log_print(ANDROID_LOG_INFO, "sssss check", " %s ",
//                        env->GetStringUTFChars(path, NULL));

    if (equal) {
        return false;
    } else {
        //应用市场分身app 过滤
        for (int i = 0; i < 5; i++) {
            jstring item = env->NewStringUTF(appList[i].c_str());
            jboolean contain = contains(env, path, item);
            if (contain) {
                return false;
            }
        }
        //小米分身过滤 /data/user/999/
        jstring conca1 = replacePath(env, tagetPath);
        jstring conca2 = replacePath(env, path);
        jboolean equal2 = equals(env, conca1, conca2);
        if (equal2) {
            return false;
        }
        return true;
    }
}

jboolean contains(JNIEnv *env, jstring str1, jstring str2) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "contains", "(Ljava/lang/CharSequence;)Z");
    jboolean booleanObject = env->CallBooleanMethod(str1, methodId, str2);
    return booleanObject;
}

jboolean equals(JNIEnv *env, jstring str1, jstring str2) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "equals", "(Ljava/lang/Object;)Z");
    jboolean booleanObject = env->CallBooleanMethod(str1, methodId, str2);
    return booleanObject;
}


jstring concat(JNIEnv *env, jstring str1, jstring str2) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "concat",
                                          "(Ljava/lang/String;)Ljava/lang/String;");
    jstring str = (jstring) env->CallObjectMethod(str1, methodId, str2);
    return str;
}

jstring replace(JNIEnv *env, jstring str1, jchar p1, jchar p2) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "replace",
                                          "(CC)Ljava/lang/String;");
    jstring str = (jstring) env->CallObjectMethod(str1, methodId, p1, p2);
    return str;
}

jint indexOf(JNIEnv *env, jstring str1, jstring p1) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "indexOf", "(Ljava/lang/String;)I");
    return env->CallIntMethod(str1, methodId, p1);
}

jstring substring(JNIEnv *env, jstring str1, jint p1) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "substring", "(I)Ljava/lang/String;");
    return (jstring) env->CallObjectMethod(str1, methodId, p1);
}

jstring substring(JNIEnv *env, jstring str1, jint p1, jint p2) {
    jclass stringClass = env->FindClass("java/lang/String");
    jmethodID methodId = env->GetMethodID(stringClass, "substring", "(II)Ljava/lang/String;");
    return (jstring) env->CallObjectMethod(str1, methodId, p1, p2);
}

jstring replacePath(JNIEnv *env, jstring tagetPath) {
    jint index1 = indexOf(env, tagetPath, env->NewStringUTF("user"));
    jstring sub1 = substring(env, tagetPath, (index1 + 5));
    jint index2 = indexOf(env, sub1, env->NewStringUTF("/"));
    jstring sub2 = substring(env, sub1, (index2 + 1));
    jstring sub3 = substring(env, tagetPath, 0, (index1 + 5));
    jstring conca1 = concat(env, sub3, sub2);
    return conca1;
}

jobject getApplication(JNIEnv *env) {
    jobject application = NULL;
    jclass activity_thread_clz = env->FindClass("android/app/ActivityThread");
    if (activity_thread_clz != NULL) {
        jmethodID currentApplication = env->GetStaticMethodID(
                activity_thread_clz, "currentApplication", "()Landroid/app/Application;");
        if (currentApplication != NULL) {
            application = env->CallStaticObjectMethod(activity_thread_clz, currentApplication);
        }
        env->DeleteLocalRef(activity_thread_clz);
    }
    return application;
}

void exitApp(JNIEnv *env) {
    jclass myClass = env->FindClass("java/lang/Runtime");
    if (myClass == nullptr) {
        return ;
    }
    jmethodID method = env->GetStaticMethodID(myClass, "getRuntime",
                                              "()Ljava/lang/Runtime;");

    jobject runtime = env->CallStaticObjectMethod(myClass, method);

    jmethodID exitMethod = env->GetMethodID(myClass, "exit", "(I)V");
    env->CallVoidMethod(runtime, exitMethod, 0);
}

bool checkException(JNIEnv *env) {
    if (env->ExceptionCheck()) {
        //输出描述错误信息
        env->ExceptionDescribe();
        //清除掉崩溃信息
        env->ExceptionClear();
        return true;
    }
    return false;
}
